# 面向过程编程：就是分析出解决问题所需要的步骤，然后用函数把这些步骤一步一步实现，使用的时候一个一个依次调用就可以了。
# 函数式：将某功能代码封装到函数中，日后便无需重复编写，仅调用函数即可
# 面向对象编程：oop[object oriented programming]是一种编程思想，设计类对象，基于类对象创建实例对象，由实例对象做具体的工作。将数据与函数绑定到一起，进行封装，这样能够更快速的开发程序，减少了重复代码的编写过程
# 类就是一个模板，模板里可以包含多个函数，函数里实现一些功能(是封装对象的特征和行为的载体，反过来说具有相同特征(属性)和行为(方法)的一类实体被称为类)。是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
# 类（Class）：类是对象的抽象，它定义了对象的属性和方法。这些属性和方法在类的所有实例之间共享。
# 对象（Object）：对象是类的实例。每个对象都有其自身的属性和方法。
# 类对象是定义实例对象的模板和蓝图，而实例对象是类对象的具体化和实例化表示
# 封装（Encapsulation）：封装是将对象的内部状态和操作方法绑定在一起，隐藏对象的内部实现细节，只通过对象提供的接口与外部进行交互。这有助于保护对象的数据不被外部代码随意修改。
# 继承（Inheritance）：继承是从已有的类派生出一个新类。新类继承了基类的属性和方法，并且可以添加或覆盖基类的行为。这使得代码重用成为可能，并且有助于构建更复杂的类层次结构。
# 多态（Polymorphism）：多态是指一个接口可以有多种实现方式。在运行时，程序可以根据对象的实际类型来决定调用哪个方法。这增加了代码的灵活性和可扩展性。
# 现实世界  对应  计算机世界
# 特征     对应    属性
# 行为     对应    方法
# 类的名称：类名
# 类的属性：一组数据(特征)
# 类的方法：允许对进行操作的方法(行为)
# 实例对象则是根据类这个模板创建的，通过实例对象可以执行类中的函数(万物皆对象)
# 类的定义：
# class 类名:
#     属性
#     方法
# 属性只是一个变量,只是它定义在类的内部;方法就是一个函数,它同样是定义在类的内部
class PersonClassName:#驼峰式命名法
    '''属性对应人的特征'''
    name='小明'#类属性
    age=20
    '''方法对应人的行为'''
    def __init__(self):
        self.name='小明'#实例属性
        pass
    def eat(self):#实例方法
        print("大口的吃饭")
        pass
    def run(self):
        print("飞快的跑")
        pass
    pass
# 创建实例对象的语法：
# 对象名=类名()
xm=PersonClassName()#类的实例化
xm.eat()#调用方法
xm.run()
print("{}的年龄是：{}".format(xm.name,xm.age))#访问类属性
# 在类的内部，使用def关键字可以定义一个实例方法：
# 定义在类里面，方法外面的属性称之为类属性，定义在方法里面使用self引用的属性称之为实例属性。
# 实例方法：
# 在类的内部，使用def关键字可以定义一个实例方法，与一般函数定义不同，实例方法必须包含参数self(可以别的名字)，且必须为第一个参数
# self参数是一个指向当前类实例本身的引用，用于访问类实例中的属性和方法。在方法调用时会自动传递实例参数self，所以传参的时候可以不用理会它。
# 创建另外一个实例对象：
xw=PersonClassName()
xw.eat()#实例方法
# 实例方法归于类的实例所有
# 属性：在类的内部定义的变量。定义在类里面，方法外面的属性称之为类属性，在方法内部定义的(格式类似self.变量名)变量称之为实例属性
# 类属性可以被类对象和实例对象访问使用(使用类名和（.）语法可以直接访问，也可以通过任何实例对象访问（尽管通常不推荐通过实例访问类属性，以避免与实例属性混淆,因为有同名的话优先访问的是实例属性而不是类属性）。)，实例属性只能由实例对象访问使用。
# 但其实在Python中，实例方法本质上是类的属性。当通过类名访问实例方法时，它处于**未绑定（Unbound）**状态，此时需要手动传入一个实例作为self参数，这样就实现了通过类名调用实例方法
# 类属性是共享的，实例属性是独立的。方法内部直接使用变量名时，优先查找局部变量（如参数），再查找实例属性，最后查找类属性。
# 实例对象是类的具体实例。它表示一个类的具体对象，通过这个类可以创建多个不同的实例对象。每个实例对象都有它自己的属性和方法，这些属性和方法是通过类中的属性和方法进行定义的。
class People:
    def __init__(self):
        '''实例属性初始值的声明'''
        self.name='小倩'
        self.sex='女生'
        self.age=20
        pass
    def eat(self):
        '''
        吃的行为
        :return:
        '''
        print('喜欢吃榴莲')
    pass
xq=People()
xq.name='小倩'#通过实例名添加实例属性，也可以修改，但不会影响其他实例中相应的实例属性的值
xq.sex='女生'
xq.age=20
xq.eat()
print(xq.name,xq.sex,xq.age)
xl=People()
xl.name='小丽'#添加实例属性
xl.sex='女生'
xl.age=2
# 如果有n个对象被实例化，那么就需要添加很多次这样的属性了，显然是比较麻烦的
xm=People()#在创建新对象的时候，自动执行初始化属性
print(xm.name)#直接输出的是初始值
xm.name='小明'#重新赋值
print(xm.name)
# __init__(self)方法，即初始化方法(__new__构造方法在__init__初始化方法前执行)，创建实例化对象的时候会自动执行这个方法，完成一些初始化设置。即在创建一个对象时默认被调用，不需要手动调用
# __init__传参：
# 改进
class People:
    def __init__(self,name,sex,age):
        '''实例属性初始值的声明'''
        self.name=name
        self.sex=sex
        self.age=age
        pass
    def eat(self,food):
        '''
        吃的行为
        :return:
        '''
        print(self.name+'喜欢吃'+food)
    pass
zp=People('张鹏','男生','18')
print(zp.name,zp.age,zp.sex)
zp.eat('香蕉')
# 总结__init__
# 1.python自带的内置函数，具有特殊的含义，开头和结尾处是两个下划线(中间没有空格)这是一种约定，旨在区分python默认方法和普通方法
# 2.是一个初始化方法，用来定义实例属性和初始化数据，创建实例对象时将提供的传参自动传递给__init__方法使用，在创建对象时自动调用，不用手动调用
# 3.利用传参的机制可以让我们定义功能更加强大并且方便的类
# self是什么？
# self和实例对象指向同一个内存地址，可以认为self就是实例对象的引用
# self使得类的实例方法可以访问和操作实例的属性和其他方法
class Person:
    def __init__(self,pro,name,food):
        '''
        初始化方法
        :param pro: 专业
        :param name: 名字
        :param food: 食物
        '''
        self.pro=pro#实例属性的定义
        self.name=name
        self.food=food
        print('init函数的执行')
        pass
    '''定义类'''
    def eat(self,name,food):
        '''实例方法'''
        print('self=%s'%(id(self)))
        print('%s喜欢吃%s专业是：%s'%(name,food,self.pro))
        pass
    def __str__(self):
        '''
        打印对象
        :return:
        '''
        return '%s喜欢吃%s专业是：%s'%(self.name,self.food,self.pro)
    def __new__(cls, *args, **kwargs):
        '''
        创建并返回实例对象的方法，每调用一次就会返回一个新的实例对象(cls就是class的缩写)
        可以控制创建对象的一些属性限定，经常用来做单例模式的时候来使用
        :param args:
        :param kwargs:
        '''
        print('new函数的执行')
        return object.__new__(cls)
    pass
#xw是一个新的实例化对象
xw=Person('心理学','小江','芒果')
print('xw=%s'%(id(xw)))
xw.eat('小王','榴莲')
# self参数是一个指向类实例本身的引用，用于访问类中的属性和方法。在方法调用时会自动传递实例参数self。
# self传参问题(名字可以更改)
# 所谓的self，可以理解为实例对象自己，某个对象调用其方法时，python解释器会把这个对象作为第一个参数传递给self，所以开发者只需要传递后面的参数即可。
# 魔术方法：
# 在python中，有一些内置好的特定的方法，方法名是"__xxx__"，在进行特定的操作时会自动被调用，无需显式调用，这些方法称之为魔术方法。
# 通过定义或重写魔术方法，你可以自定义类的行为，包括初始化、析构、属性访问、运算符重载等。
# __init__方法：在对象实例化时调用，用于初始化对象的属性。
# __str__方法：用于定义对象的字符串表示形式。其主要作用是在使用str()函数或print()函数输出对象时，返回一个易于阅读的字符串，以便更好地了解对象的状态或内容。
  # 如果没有重写这个方法直接打印对象，Python会调用基类object的 __str__ 方法，输出结果是一串类似id地址的信息。
print(xw)#直接输出对象
# __lt__ 方法：是Python中的一个魔术方法（或特殊方法），用于定义实例对象的“小于”比较行为。这意味着当你使用 < 运算符比较两个对象时，Python 会调用这个方法。
# __le__ 方法是：Python 中的一个魔术方法，用于定义实例对象的“小于等于”比较行为。这意味着当你使用 <= 运算符比较两个对象时，Python 会调用这个方法。
# 在默认情况下，如果你没有为类定义 __ge__ 方法，但定义了 __le__ 方法，Python 可以通过逻辑反转来推导 >= 的结果，__lt__也是如此。
# __eq__ 方法是Python中的一个魔术方法，用于定义实例对象的“等于”比较行为。这意味着当你使用 == 运算符比较两个对象时，Python 会调用这个方法。
# __new__方法：实例化方法，构造方法，创建并返回一个新的实例对象，每调用一次，就会返回一个新的实例对象，是空对象。
# 通常来说，当前类开始实例化时，new()方法会返回cls（cls指代当前类）的实例，然后该类的init()方法作为初始化方法会接收这个实例（即self）作为自己的第一个参数，然后依次传入new ()方法中接收的位置参数和命名参数。
# __new__和__init__的区别：
  # __new__类的实例化方法，构造方法，必须要返回该实例，这样对象才能创建成功。(执行早于init，方法必须包含cls代表要实例化的类，此参数在实例化时自动传递)
  # __init__用来做数据属性的初始化工作，是实例的初始化方法，接受类的实例self并对其进行初始化。
# __class__方法：获得已知对象的类(对象__class__)。
# __del__方法：对象在程序运行结束后进行对象销毁的时候调用这个方法，来释放资源。
# 析构方法的概述：
# 当一个对象被删除或销毁即程序执行完毕时，python解释器会自动调用一个方法，这个方法为__del__()方法，也称为析构方法。
class Animal:
    def __init__(self,name):
        self.name=name
        print('这是初始化方法')
        pass
    def __del__(self):
        #主要工作就是来操作对象的释放，一旦释放完毕就不能再使用
        print('当在某个作用域下面没有被使用(引用)的情况下，解释器会自动调用此函数来释放内存空间')
        print('这是析构方法')
        print('%s这个对象被彻底销毁了，内存空间释放了'%self.name)
    pass
cat=Animal('小花猫')
del cat#使用del语句手动删除对象
# 无论是手动销毁，还是 Python 自动帮我们销毁，都会调用 __del__() 方法，且不论有没有__del__()方法都会调用
# input('程序等待中......')
print('*'*40)
dog=Animal('柯基')
# Object类规定了python用于类的内置函数，以下会简述几个比较常见的用法。
# __new__(cls, *args, **kwargs)
# 创建对象时自动调用的函数，主要作用是创建对象，给该对象分配空间，方便之后的的操作。该函数会返回创建出来的对象实体，一旦正常地返回实体后，调用初始化函数
# __init__(self)
# 初始化函数（构造函数），作用：给当前对象创建各类变量，并给变量赋初始值，一般用于对象的初始设置，该函数没有返回值。
# __str__(self)
# 对象描述函数，作用：返回当前对象的字符串类型的信息描述，一般用于对象的直接输出显示。
# __del__(self)
# 删除该对象时会自动调用，一般用于工具型对象的资源回收。
# __repr__(self)
# 类似__str__，只是该函数是面向解释器的。
# __call__(self)
# 该方法的功能类似于在类中重载()运算符，使得类实例对象可以像调用普通函数那样，以“对象名()”的形式使用。
# 断言：assert语法用于判断代码是否符合预期，否则引发断言错误
assert 1 + 1 == 2
# 非传统方式创建类(基于type创建类)：
# 1，类名 2，继承关系 3，成员
Fa = type("Foo", (object,), {"v1": 123, "func": lambda self: 666})
# 元类；指定类由谁来创建(默认的元类是type，当你定义一个类时，如果不指定元类，Python就会使用type作为这个类的元类。)

